using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;

namespace Zsa.Emulation.Cartridge
{
    /// <summary>
    /// Delegate for cart found event.
    /// </summary>
    /// <param name="count"></param>
    /// <param name="total"></param>
    /// <param name="fileInfo"></param>
    public delegate void CartFoundHandler(int count, int total,
       CartridgeFileInfo fileInfo);

    /// <summary>
    /// Converts between differnt cart formats.
    /// </summary>
    public static class DumpManager
    {

        #region Fields
        /// <summary>
        /// Used to read carts with different dump formats.
        /// </summary>
        private static CartDumpReaderWriter[] _DumpReader =
            new CartDumpReaderWriter[]
            {
                new iNesCartDumpReader()
            };
        #endregion Fields

        #region Methods

        #region Convert Cart Methods
        /// <summary>
        /// 
        /// </summary>
        /// <param name="cart"></param>
        /// <param name="cartWriter"></param>
        public static void Convert(Cart cart,
            CartDumpReaderWriter cartWriter, string fileName)
        {
            Convert(cart,
                cartWriter,
                new FileStream(fileName,FileMode.CreateNew,FileAccess.Write)
            );
        }

        /// <summary>
        /// Converts the specified cart.
        /// </summary>
        /// <param name="cart">The cart.</param>
        /// <param name="cartWriter">The cart writer.</param>
        /// <param name="stream">The stream.</param>
        public static void Convert(Cart cart,
            CartDumpReaderWriter cartWriter, Stream stream)
        {
            Convert(cart,cartWriter, stream, true);
        }

        /// <summary>
        /// Converts the specified cart.
        /// </summary>
        /// <param name="cart">The cart.</param>
        /// <param name="cartWriter">The cart writer.</param>
        /// <param name="stream">The stream.</param>
        /// <param name="closeStream">if set to <c>true</c> [close stream].</param>
        public static void Convert(Cart cart,
            CartDumpReaderWriter cartWriter, Stream stream, bool closeStream)
        {
            cartWriter.Write(cart, stream);
            if (closeStream)
            {
                stream.Flush();
                stream.Close();
            }
        }

        #endregion Convert Cart Methods

        #region Load Cart Methods
        /// <summary>
        /// Loads the file and returns the cart.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <returns></returns>
        public static Cart LoadCart(string fileName)
        {
            if (fileName == null)
            {
                throw new ArgumentNullException(
                    "fileName",
                    "The file name argument cannot be null !"
                    );
            }
            if (fileName == string.Empty)
            {
                throw new ArgumentException(
                    "The file name argument cannot be null !",
                    "fileName"
                    );
            }
            FileStream _FileStream =
                new FileStream(
                    fileName,
                    FileMode.Open,
                    FileAccess.Read,
                    FileShare.Read
                );
            Cart _Cart = null;
            CartridgeFileInfo _CartInfo;
            for (int _TempIndex = 0; _TempIndex < _DumpReader.Length; _TempIndex++)
            {
                if (!_DumpReader[_TempIndex].TryGetInfo(_FileStream, out _CartInfo))
                {
                    continue;
                }
                _Cart = _DumpReader[_TempIndex].Load(_FileStream);
                if (_Cart != null)
                {
                    break;
                }
            }
            if (_Cart == null)
            {
                throw new UnsupportedCartridgeFormatException(fileName);
            }
            return _Cart;
        }


        /// <summary>
        /// Trys to get the cart info.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="cartInfo">The cart info.</param>
        /// <returns></returns>
        public static bool TryGetCartInfo(string fileName, out CartridgeFileInfo cartInfo)
        {
            if (fileName == null)
            {
                throw new ArgumentNullException(
                    "fileName",
                    "The file name argument cannot be null !"
                    );
            }
            if (fileName == string.Empty)
            {
                throw new ArgumentException(
                    "The file name argument cannot be null !",
                    "fileName"
                    );
            }
            cartInfo = null;
            FileStream _FileStream =
                new FileStream(
                    fileName,
                    FileMode.Open,
                    FileAccess.Read,
                    FileShare.Read
                );
            try
            {
                for (int _TempIndex = 0; _TempIndex < _DumpReader.Length; _TempIndex++)
                {
                    if (_DumpReader[_TempIndex].TryGetInfo(_FileStream, out cartInfo))
                    {
                        return true;
                    }

                }
            }
            catch (Exception excep)
            {
                Console.WriteLine(excep);
            }
            return false;

        }
        #endregion Load Cart Methods

        #region Scan Carts
        /// <summary>
        /// Scans the directory.
        /// </summary>
        /// <param name="directory">The directory.</param>
        /// <param name="cartFoundHandler">The cart found handler.</param>
        /// <returns></returns>
        public static CartridgeFileInfoCollection ScanDirectory(string directory, CartFoundHandler cartFoundHandler)
        {
            // Get the files in the folder.
            return ScanFiles(Directory.GetFiles(directory), cartFoundHandler);
        }

        /// <summary>
        /// Scans a directory for roms.
        /// </summary>
        /// <param name="directory">The directory.</param>
        /// <returns></returns>
        public static CartridgeFileInfoCollection ScanFiles(string[] files, CartFoundHandler cartFoundHandler)
        {
            // Make the cart array the size of the files.
            CartridgeFileInfoCollection _CartInfoList = new CartridgeFileInfoCollection(files.Length);
            //Temp cart info
            CartridgeFileInfo _CartInfo;
            // The total files.
            int _TotalFiles = 0;
            // Loop through the files.
            for (int _TempIndex = 0; _TempIndex < files.Length; _TempIndex++)
            {
                // Get the cartridge info.
                if (TryGetCartInfo(files[_TempIndex], out _CartInfo))
                {
                    // If the cart founnd handler is not null then invoke.
                    //if (cartFoundHandler != null)
                    //{
                    //    cartFoundHandler(_TempIndex, _TotalFiles, _CartInfo);
                    //}
                    // Add the cartridge to the list.
                    _CartInfoList.Add(_CartInfo);
                }
            }
            return _CartInfoList;
        }
        #endregion Scan Carts


        #endregion Methods
    }
}
